package l1j.server.echo;

import java.io.IOException;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.encryptions.Encryption;
import l1j.server.server.serverpackets.ServerBasePacket;
import l1j.server.server.types.UByte8;
import l1j.server.server.types.UChar8;


/**
 * 封包輸出管理
 * @author dexc
 *
 */
public class PacketSc implements Runnable {

	private static final Logger _log = Logger.getLogger(PacketSc.class.getName());


	private final Queue<byte[]> _queue;// 隊列

	private final ClientThread _client;

	private final EncryptExecutor _executor;

	private final Encryption _keys;

	public PacketSc(ClientThread client, EncryptExecutor executor) {
		this._client = client;
		this._keys = client.get_keys();
		this._executor = executor;
		// 创建一个最初为空的 ConcurrentLinkedQueue。
		this._queue = new ConcurrentLinkedQueue<byte[]>();
	}

	/**
	 * 加密封包
	 * @param packet
	 * @throws Exception
	 */
	public void encrypt(final ServerBasePacket packet) throws Exception {
		byte[] encrypt = packet.getContent();
		//_log.info("加密封包: 長度: "+encrypt.length);
		if (encrypt.length > 0 && this._executor.out() != null) {
			final int opid = encrypt[0];
			if (opid == -1) {
				_log.log(Level.SEVERE ,"拒絕發送: " + packet.getType() + " OPID: " + opid);
				return;
			}
//						System.out.println("[Server] opcode = " + Math.abs(opid) +" / "+ packet.toString());//opqlo

			char ac[] = new char[encrypt.length];
			ac = UChar8.fromArray(encrypt);
			// 加密
			if(ac.length <=3){
				return;
			}
			ac = this._keys.encrypt(ac);
			if (ac == null) {
				return;
			}
			encrypt = UByte8.fromArray(ac);

			this.requestWork(encrypt);
		}
	}

	/**
	 * 輸出封包
	 * @param decrypt
	 */
	private void outPacket(final byte[] decrypt) {
		if(this._client.get_socket() !=null){
			try {
				final int outLength = decrypt.length + 2;
				// 將指定的位元組寫入此輸出流。
				this._executor.out().write(outLength & 0xff);
				this._executor.out().write(outLength >> 8 & 0xff);
				// 將 decrypt.length 個位元組從指定的 byte 陣列寫入此輸出流。
				this._executor.out().write(decrypt);
				// 刷新此輸出流並強制寫出所有緩衝的輸出位元組。
				this._executor.out().flush();

				/*long tt = System.currentTimeMillis();
			_log.info("加密封包: 長度: "+decrypt.length+"/"+(tt - _client.TTL.get(1)));
			_client.TTL.put(1, tt);*/

			} catch (final IOException e) {
				// 輸出異常
				//_log.error(e.getLocalizedMessage(), e);
				this._executor.stop();
			}
		}
	}

	/**
	 * 加入工作列隊
	 * @param data
	 */
	private void requestWork(final byte data[]) {
		this._queue.offer(data);
	}

	@Override
	public void run() {
		try {
			while (this._client.get_socket() != null) {
				for (final Iterator<byte[]> iter = this._queue.iterator(); iter.hasNext();) {
					final byte[] decrypt = iter.next();// 返回迭代的下一个元素。
					// 从迭代器指向的 collection 中移除迭代器返回的最后一个元素
					iter.remove();
					this.outPacket(decrypt);
					Thread.sleep(1);
				}
				// 隊列為空 休眠
				Thread.sleep(10);
			}
			//finalize();

		} catch (final Exception e) {
			_log.log(Level.SEVERE ,e.getLocalizedMessage(), e);

			/*} catch (Throwable e) {
			_log.error(e.getLocalizedMessage(), e);//*/

		} finally {
			// 移除此 collection 中的所有元素
			this._queue.clear();
		}
	}

	public void stop() {
		// 移除此 collection 中的所有元素
		this._queue.clear();
	}
}